#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author: kerlomz <kerlomz@gmail.com>
import io
import json
import random
import time

import shutil

import cv2
import numpy as np
import PIL.Image as PIL_Image
import tensorflow as tf
from importlib import import_module
from config import *
from constants import RunMode
from pretreatment import preprocessing
from framework import GraphOCR

import requests
from selenium import webdriver
import sys


def get_image_batch(img_bytes):

    def load_image(image_bytes):
        data_stream = io.BytesIO(image_bytes)
        pil_image = PIL_Image.open(data_stream)
        rgb = pil_image.split()
        size = pil_image.size

        if len(rgb) > 3 and REPLACE_TRANSPARENT:
            background = PIL_Image.new('RGB', pil_image.size, (255, 255, 255))
            background.paste(pil_image, (0, 0, size[0], size[1]), pil_image)
            pil_image = background

        if IMAGE_CHANNEL == 1:
            pil_image = pil_image.convert('L')

        im = np.array(pil_image)
        im = preprocessing(im, BINARYZATION, SMOOTH, BLUR).astype(np.float32)
        if RESIZE[0] == -1:
            ratio = RESIZE[1] / size[1]
            resize_width = int(ratio * size[0])
            im = cv2.resize(im, (resize_width, RESIZE[1]))
        else:
            im = cv2.resize(im, (RESIZE[0], RESIZE[1]))
        im = im.swapaxes(0, 1)
        return (im[:, :, np.newaxis] if IMAGE_CHANNEL == 1 else im[:, :]) / 255.

    return [load_image(index) for index in [img_bytes]]


def decode_maps(charset):
    return {index: char for index, char in enumerate(charset, 0)}


def predict_func(image_batch, _sess, dense_decoded, op_input):
    dense_decoded_code = _sess.run(dense_decoded, feed_dict={
        op_input: image_batch,
    })
    decoded_expression = []
    for item in dense_decoded_code:
        expression = ''

        for char_index in item:
            if char_index == -1:
                expression += ''
            else:
                expression += decode_maps(GEN_CHAR_SET)[char_index]
        decoded_expression.append(expression)
    return ''.join(decoded_expression) if len(decoded_expression) > 1 else decoded_expression[0]


class Config(object):
    base_dir = 'D:' '\\'

    @staticmethod
    def get_log_path_error():
        return Config.base_dir + '4399_error.log'

    @staticmethod
    def get_log_path_csv():
        return Config.base_dir + '4399_check.csv'

    @staticmethod
    def get_captcha_server_url():
        return 'http://192.168.2.88:6000/b'


def my_log(log_info, lv='D'):
    if lv == 'D':
        print(log_info)
    if lv == 'I':
        print(log_info)
    if lv == 'E':
        print(log_info)
        # with open(Config.get_log_path_error(), 'a+') as wf:
        #     wf.write(log_info)
        #     wf.write('\n')


class Verify(object):

    def __init__(self):
        MODEL_PATH = r'D:\_ALL\CODE\gitee\constellations\Aquarius\df\captcha_battle_net_lsmt\model_bn_accuracy_0.145'
        graph = tf.Graph()
        tf_checkpoint = tf.train.latest_checkpoint(MODEL_PATH)
        sess = tf.Session(
            graph=graph,
            config=tf.ConfigProto(
                # allow_soft_placement=True,
                # log_device_placement=True,
                gpu_options=tf.GPUOptions(
                    allocator_type='BFC',
                    # allow_growth=True,  # it will cause fragmentation.
                    per_process_gpu_memory_fraction=0.01
                ))
        )
        graph_def = graph.as_graph_def()

        with graph.as_default():
            sess.run(tf.global_variables_initializer())
            # with tf.gfile.GFile(COMPILE_MODEL_PATH.replace('.pb', '_{}.pb'.format(int(0.95 * 10000))), "rb") as f:
            #     graph_def_file = f.read()
            # graph_def.ParseFromString(graph_def_file)
            # print('{}.meta'.format(tf_checkpoint))
            model = GraphOCR(
                RunMode.Predict,
                NETWORK_MAP[NEU_CNN],
                NETWORK_MAP[NEU_RECURRENT]
            )
            model.build_graph()
            saver = tf.train.Saver(tf.global_variables())

            saver.restore(sess, tf.train.latest_checkpoint(MODEL_PATH))
            _ = tf.import_graph_def(graph_def, name="")

        self.dense_decoded_op = sess.graph.get_tensor_by_name("dense_decoded:0")
        self.x_op = sess.graph.get_tensor_by_name('input:0')
        sess.graph.finalize()
        self.sess = sess

    def get_predict(self, pic_path):
        with open(pic_path, "rb") as f:
            b = f.read()

        batch = get_image_batch(b)
        predict_text = predict_func(
            batch,
            self.sess,
            self.dense_decoded_op,
            self.x_op,
        )
        return predict_text


g_verify = Verify()


class Client(object):
    tmp_captcha_file_name = 'captcha.png'
    tmp_captcha_path = r'N:\_TMP\captcha_prj_bn_lsmt\predict_testing' '\\'
    tmp_captcha_binarizing_path = r'N:\_TMP\captcha_prj_bn_lsmt\predict_testing_binarizing' '\\'
    tmp_captcha_result_path = r'N:\_TMP\captcha_prj_bn_lsmt\predict_testing_result' '\\'

    def __init__(self, unit):
        self.uid = unit['id']
        self.gid = unit['gid']
        self.username = unit['account']
        self.password = unit['passwd']
        self.msg = 'undefined'
        self.rapid_info = ''

        self.browser = webdriver.Chrome()
        self.browser.implicitly_wait(3)

        # """http://ptlogin.4399.com/ptlogin/loginFrame.do?postLoginHandler=default&redirectUrl=&displayMode=undefined&css=%2F%2Fs1.img4399.com%2Fwebgame%2Fssjj%2Fnews%2Fcss%2Fptlogin.css%3Fecb1e6f&appId=ssjj&gameId=news&username=&externalLogin=qq&password=&mainDivId=popup_login_div&autoLogin=false&includeFcmInfo=false&qrLogin=true&userNameLabel=4399%E7%94%A8%E6%88%B7%E5%90%8D&userNameTip=%E8%AF%B7%E8%BE%93%E5%85%A54399%E7%94%A8%E6%88%B7%E5%90%8D&welcomeTip=%E6%AC%A2%E8%BF%8E%E5%9B%9E%E5%88%B04399&v=1559703823792"""
        # self.login_url = 'https://www.battlenet.com.cn/login/zh/'
        self.login_url = 'https://kr.battle.net/login/en/login.app?app=app'
        self.browser.get(self.login_url)
        my_log(self.login_url)

    def __del__(self):
        self.browser.close()

    def _log(self):
        return
        # with open(r'N:\4399_check.json', 'a+') as wf:
        #     msg = '{"id":"%s", "username":"%s", "msg":"%s", "rapid_info":"%s"},' % (self.uid, self.username, self.msg, self.rapid_info)
        #     wf.write(msg)
        with open(Config.get_log_path_csv(), 'a+') as wf:
            msg = '%s\t%s\t%s\t%s\t%s\t%s\n' % (self.uid, self.gid, self.username, self.password, self.msg, self.rapid_info)
            wf.write(msg)

        # PhpApi().receiveHaoAccount(self.uid, self.gid, self.username, self.msg, self.rapid_info)

    @staticmethod
    def captcha_req(bytes_png):
        # 保存文件，二值化
        with open(r'N:\_TMP\captcha_prj_bn_lsmt\predict_testing\captcha.png', 'wb') as wf:
            wf.write(bytes_png)

        # D:\_ALL\CODE\gitee\constellations\Aquarius\df\captcha\binarizing.py
        sys.path.append(r'D:\_ALL\CODE\gitee\constellations\Aquarius\df\captcha')
        import binarizing
        binarizing.do_binarizing_file(Client.tmp_captcha_path + Client.tmp_captcha_file_name,
                                      Client.tmp_captcha_binarizing_path + Client.tmp_captcha_file_name)

        return g_verify.get_predict(Client.tmp_captcha_binarizing_path + Client.tmp_captcha_file_name)

        with open(Client.tmp_captcha_binarizing_path + Client.tmp_captcha_file_name, "rb") as f:
            b = f.read()

        batch = get_image_batch(b)
        predict_text = predict_func(
            batch,
            self.sess,
            dense_decoded_op,
            x_op,
        )
        return predict_text

        # 识别
        url = Config.get_captcha_server_url()
        files = {'image_file': ('demo.png', BytesIO(bytes_png), 'application')}
        r = requests.post(url=url, files=files)

        # 识别结果
        # print("接口响应: {}".format(r.text))
        predict_text = json.loads(r.text)["value"]
        return predict_text

    def deal_once(self):
        # 00 参数预处理，密码非ascii的时候直接报错
        if self.password.find('\\x') != -1:
            my_log('【Info】密码非ascii', lv='I')
            self.msg = 'df-Invalidate_Password'
            return True

        self.browser.execute_script("""$('#login-input-container').attr('class', ''); $('#login-input-container').attr('style', '');""")
        time.sleep(1)
        # self.browser.find_element_by_id('accountName').send_keys('111111@qq.com')
        # password = self.browser.find_element_by_id('password')
        str_password = ''.join([chr(random.randint(ord('a'), ord('z'))) for i in range(random.randint(7, 9))])
        # password.send_keys(str_password)
        str_password = '123456'
        self.browser.execute_script(
            """$('#accountName').val('111111@qq.com'); $('#password').val('%s');""" % str_password)
        time.sleep(1)

        # 01 检测是否有验证码
        try:
            captcha = self.browser.find_element_by_id('sec-string')
            if captcha:
                predict_text = self.captcha_req(captcha.screenshot_as_png)
                # self.browser.find_element_by_id('captchaInput').send_keys(predict_text)
                self.browser.execute_script("""$('#captchaInput').val('%s');""" % predict_text)
                time.sleep(1)
                my_log('【验证码】uid, predict_text = %s, %s' % (self.uid, predict_text), lv='D')
            else:
                self.browser.find_element_by_id('submit').click()
                return False
        except Exception as e:
            pass

        # 02 点击
        self.browser.find_element_by_id('submit').click()

        # 03 判断结果：成功
        # if self.browser.find_element_by_id('m_all_ser'):
        """
        try:
            errors = self.browser.find_element_by_id('display-errors')
            if errors:
                errors_info = errors.text
                my_log('{"msg":"%s", "quick_data":"%s"}' % ('success', rapid_info), lv='I')
                my_log('【Info】验证成功', lv='I')
                self.msg = 'success'
                self.rapid_info = rapid_info['value']
                return True
        except Exception:
            # my_log('{"uid":"%s", "msg":"%s", "quick_data":"%s"}' % (self.uid, 'except', ''), lv='E')
            pass
        """
        # js-errors需要刷新（稍等）重试
        try:
            js_errors = self.browser.find_element_by_id('js-errors')
            if js_errors:
                errors_info = js_errors.text
                if errors_info == '重试次数过多。请稍后重试。':
                    self.browser.get(self.login_rul)
                    return False
                if errors_info == 'You\'ve made too many attempts. Please try again later.':
                    self.browser.get(self.login_rul)
                    return False
        except Exception as e:
            # my_log('{"uid":"%s", "msg":"%s", "quick_data":"%s"}' % (self.uid, 'except', ''), lv='E')
            pass

        # 判断结果：失败，密码错误、用户不存在、
        """
        'We can\\'t find that Blizzard Account.\nCreate a free Blizzard Account'
        """
        err_msg = self.browser.find_element_by_id('display-errors')
        str_err_msg = err_msg.get_attribute('textContent')
        if str_err_msg.find('Wrong code entered. Please try again.') != -1:
            return False
        if str_err_msg.find('Please enter your password.') != -1:
            return False
        if str_err_msg.find('You\'ve made too many attempts.') != -1:
            return True
        if str_err_msg.find('We can\'t find that Blizzard Account.') != -1:
            return True

        # 答案对了，保存
        if len(predict_text) > 0:
            shutil.copyfile(Client.tmp_captcha_path + Client.tmp_captcha_file_name,
                                      Client.tmp_captcha_result_path + predict_text + '.png')
        """
        if err_msg.text == '请输入密码。' or err_msg.text == '输入包含错误字符。请重试。' or err_msg.text == '重试次数过多。请稍后重试。':
            self.msg = err_msg.text
            my_log('{"uid":"%s", msg":"%s", "quick_data":"%s"}' % (self.uid, err_msg.text, ''), lv='E')
            return True
        if err_msg.text == '' or err_msg.text == '验证码为空' or err_msg.text == '验证码错误' or err_msg.text == '账号异常，请出入验证码':
            my_log('【Info】验证码有误，请重试', lv='I')
            return False
        my_log('{"uid":"%s", msg":"%s", "quick_data":"%s"}' % (self.uid, err_msg.text, ''), lv='E')
        """
        # os.system('PAUSE')
        # self.browser.close()

    def Run(self):
        for i in range(5000):
            try:
                if self.deal_once():
                    break
                time.sleep(1)
            except Exception as e:
                my_log('【Exception】self.deal_once(unit)。' + str(e), lv='E')
                pass

        self._log()


def main():
    unit = {'id': '00000000', 'gid': '01234567', 'account': '123456789@qq.com', 'passwd': '1234567', }
    Client(unit).Run()


if __name__ == '__main__':
    main()
    exit(-1)

    if WARP_CTC:
        import_module('warpctc_tensorflow')
    graph = tf.Graph()
    tf_checkpoint = tf.train.latest_checkpoint(MODEL_PATH)
    sess = tf.Session(
        graph=graph,
        config=tf.ConfigProto(
            # allow_soft_placement=True,
            # log_device_placement=True,
            gpu_options=tf.GPUOptions(
                allocator_type='BFC',
                # allow_growth=True,  # it will cause fragmentation.
                per_process_gpu_memory_fraction=0.01
            ))
    )
    graph_def = graph.as_graph_def()

    with graph.as_default():
        sess.run(tf.global_variables_initializer())
        # with tf.gfile.GFile(COMPILE_MODEL_PATH.replace('.pb', '_{}.pb'.format(int(0.95 * 10000))), "rb") as f:
        #     graph_def_file = f.read()
        # graph_def.ParseFromString(graph_def_file)
        # print('{}.meta'.format(tf_checkpoint))
        model = GraphOCR(
            RunMode.Predict,
            NETWORK_MAP[NEU_CNN],
            NETWORK_MAP[NEU_RECURRENT]
        )
        model.build_graph()
        saver = tf.train.Saver(tf.global_variables())

        saver.restore(sess, tf.train.latest_checkpoint(MODEL_PATH))
        _ = tf.import_graph_def(graph_def, name="")

    dense_decoded_op = sess.graph.get_tensor_by_name("dense_decoded:0")
    x_op = sess.graph.get_tensor_by_name('input:0')
    sess.graph.finalize()

    # Fill in your own sample path
    image_dir = r"N:\_TMP\captcha_prj_bn_lsmt\predict_testing_binarizing"
    for i, p in enumerate(os.listdir(image_dir)):
        n = os.path.join(image_dir, p)
        if i > 1000:
            break
        with open(n, "rb") as f:
            b = f.read()

        batch = get_image_batch(b)
        predict_text = predict_func(
            batch,
            sess,
            dense_decoded_op,
            x_op,
        )

        print(i, p, predict_text)
        if p.startswith(predict_text):
            print('【Success】')

